package pl.charmas.android.reactivelocation.sample; import android.content.Intent; import android.content.IntentSender; import android.location.Address; import android.location.Location; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.common.api.Status; import com.google.android.gms.location.ActivityRecognitionResult; import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationSettingsRequest; import com.google.android.gms.location.LocationSettingsResult; import com.google.android.gms.location.LocationSettingsStates; import com.google.android.gms.location.LocationSettingsStatusCodes; import java.util.List; import pl.charmas.android.reactivelocation.ReactiveLocationProvider; import pl.charmas.android.reactivelocation.sample.utils.AddressToStringFunc; import pl.charmas.android.reactivelocation.sample.utils.DetectedActivityToString; import pl.charmas.android.reactivelocation.sample.utils.DisplayTextOnViewAction; import pl.charmas.android.reactivelocation.sample.utils.LocationToStringFunc; import pl.charmas.android.reactivelocation.sample.utils.ToMostProbableActivity; import rx.Observable; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.functions.Action1; import rx.functions.Func1; import rx.schedulers.Schedulers; import static pl.charmas.android.reactivelocation.sample.utils.UnsubscribeIfPresent.unsubscribe; public class MainActivity extends BaseActivity { private final static int REQUEST_CHECK_SETTINGS = 0; private final static String TAG = "MainActivity"; private ReactiveLocationProvider locationProvider; private TextView lastKnownLocationView; private TextView updatableLocationView; private TextView addressLocationView; private TextView currentActivityView; private Observable<Location> lastKnownLocationObservable; private Observable<Location> locationUpdatesObservable; private Observable<ActivityRecognitionResult> activityObservable; private Subscription lastKnownLocationSubscription; private Subscription updatableLocationSubscription; private Subscription addressSubscription; private Subscription activitySubscription; private Observable<String> addressObservable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lastKnownLocationView = (TextView) findViewById(R.id.last_known_location_view); updatableLocationView = (TextView) findViewById(R.id.updated_location_view); addressLocationView = (TextView) findViewById(R.id.address_for_location_view); currentActivityView = (TextView) findViewById(R.id.activity_recent_view); locationProvider = new ReactiveLocationProvider(getApplicationContext()); lastKnownLocationObservable = locationProvider.getLastKnownLocation(); final LocationRequest locationRequest = LocationRequest.create() .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) .setNumUpdates(5) .setInterval(100); locationUpdatesObservable = locationProvider .checkLocationSettings( new LocationSettingsRequest.Builder() .addLocationRequest(locationRequest) .setAlwaysShow(true) //Refrence: http://stackoverflow.com/questions/29824408/google-play-services-locationservices-api-new-option-never .build() ) .doOnNext(new Action1<LocationSettingsResult>() { @Override public void call(LocationSettingsResult locationSettingsResult) { Status status = locationSettingsResult.getStatus(); if (status.getStatusCode() == LocationSettingsStatusCodes.RESOLUTION_REQUIRED) { try { status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS); } catch (IntentSender.SendIntentException th) { Log.e("MainActivity", "Error opening settings activity.", th); } } } }) .flatMap(new Func1<LocationSettingsResult, Observable<Location>>() { @Override public Observable<Location> call(LocationSettingsResult locationSettingsResult) { return locationProvider.getUpdatedLocation(locationRequest); } }); addressObservable = locationProvider.getUpdatedLocation(locationRequest) .flatMap(new Func1<Location, Observable<List<Address>>>() { @Override public Observable<List<Address>> call(Location location) { return locationProvider.getReverseGeocodeObservable(location.getLatitude(), location.getLongitude(), 1); } }) .map(new Func1<List<Address>, Address>() { @Override public Address call(List<Address> addresses) { return addresses != null && !addresses.isEmpty() ? addresses.get(0) : null; } }) .map(new AddressToStringFunc()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); activityObservable = locationProvider.getDetectedActivity(50); } @Override protected void onLocationPermissionGranted() { lastKnownLocationSubscription = lastKnownLocationObservable .map(new LocationToStringFunc()) .subscribe(new DisplayTextOnViewAction(lastKnownLocationView), new ErrorHandler()); updatableLocationSubscription = locationUpdatesObservable .map(new LocationToStringFunc()) .map(new Func1<String, String>() { int count = 0; @Override public String call(String s) { return s + " " + count++; } }) .subscribe(new DisplayTextOnViewAction(updatableLocationView), new ErrorHandler()); addressSubscription = addressObservable .subscribe(new DisplayTextOnViewAction(addressLocationView), new ErrorHandler()); activitySubscription = activityObservable .map(new ToMostProbableActivity()) .map(new DetectedActivityToString()) .subscribe(new DisplayTextOnViewAction(currentActivityView), new ErrorHandler()); } @Override protected void onStop() { super.onStop(); unsubscribe(updatableLocationSubscription); unsubscribe(addressSubscription); unsubscribe(lastKnownLocationSubscription); unsubscribe(activitySubscription); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add("Geofencing").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { startActivity(new Intent(MainActivity.this, GeofenceActivity.class)); return true; } }); menu.add("Places").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { if (TextUtils.isEmpty(getString(R.string.API_KEY))) { Toast.makeText(MainActivity.this, "First you need to configure your API Key - see README.md", Toast.LENGTH_SHORT).show(); } else { startActivity(new Intent(MainActivity.this, PlacesActivity.class)); } return true; } }); menu.add("Mock Locations").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { startActivity(new Intent(MainActivity.this, MockLocationsActivity.class)); return true; } }); return true; } private class ErrorHandler implements Action1<Throwable> { @Override public void call(Throwable throwable) { Toast.makeText(MainActivity.this, "Error occurred.", Toast.LENGTH_SHORT).show(); Log.d("MainActivity", "Error occurred", throwable); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);//intent); switch (requestCode) { case REQUEST_CHECK_SETTINGS: //Reference: https://developers.google.com/android/reference/com/google/android/gms/location/SettingsApi switch (resultCode) { case RESULT_OK: // All required changes were successfully made Log.d(TAG, "User enabled location"); break; case RESULT_CANCELED: // The user was asked to change settings, but chose not to Log.d(TAG, "User Cancelled enabling location"); break; default: break; } break; } } }